home *** CD-ROM | disk | FTP | other *** search
/ MacAddict 84 / MacAddict_084_2003_08.iso / pc / Software / Audio & Music / Audacity 1.1.3.dmg / nyquist / seqmidi.lsp < prev    next >
Lisp/Scheme  |  2002-09-16  |  6KB  |  160 lines

  1. ;; seqmidi.lsp -- functions to use MIDI files in Nyquist
  2. ;
  3. ; example call:
  4. ; (seq-midi my-seq
  5. ;   (note (chan pitch velocity) (= chan 2) (my-note pitch velocity))
  6. ;   (ctrl (chan control value) (...))
  7. ;   (bend (chan value) (...))
  8. ;   (touch (chan value) (...))
  9. ;   (prgm (chan value) (setf (aref my-prgm chan) value))
  10.  
  11. ;; seq-midi - a macro to create a sequence of sounds based on midi file
  12. ;
  13. (defmacro seq-midi (the-seq &rest cases)
  14.   (seq-midi-cases-syntax-check cases)
  15.   `(let (_the-event _next-time _the-seq _seq-midi-closure _nyq-environment 
  16.          _the-seq _tag)
  17.     (setf _the-seq (seq-copy ,the-seq))
  18.     (setf _nyq-environment (nyq:the-environment))
  19.     (setf _seq-midi-closure #'(lambda (t0)
  20.       ; (format t "_seq_midi_closure: t0 = ~A~%" t0)
  21.       (prog (_the-sound)
  22. loop    ; go forward until we find note to play (we may be there)
  23.         ; then go forward to find time of next note
  24.         (setf _the-event (seq-get _the-seq))
  25.         ; (display "seq-midi" _the-event t0)
  26.         (setf _tag (seq-tag _the-event))
  27.         (cond ((= _tag seq-ctrl-tag)
  28.                ,(make-ctrl-handler cases))
  29.               ((= _tag seq-bend-tag)
  30.                ,(make-bend-handler cases))
  31.               ((= _tag seq-touch-tag)
  32.                ,(make-touch-handler cases))
  33.               ((= _tag seq-prgm-tag)
  34.                ,(make-prgm-handler cases))
  35.               ((= _tag seq-done-tag)
  36.                ; (format t "_seq_midi_closure: seq-done")
  37.                (cond (_the-sound ; this is the last sound of sequence
  38.                       ; (format t "returning _the-sound~%")
  39.                       (return _the-sound))
  40.                      (t ; sequence is empty, return silence
  41.                       ; (format t "returning snd-zero~%")
  42.                       (return (snd-zero t0 *sound-srate*)))))
  43.               ((and (= _tag seq-note-tag)
  44.                     ,(make-note-test cases))
  45.                (cond (_the-sound ; we now have time of next note
  46.                       (setf _next-time (/ (seq-time _the-event) 1000.0))
  47.                       (go exit-loop))
  48.                      (t
  49.                       (setf _the-sound ,(make-note-handler cases))))))
  50.         (seq-next _the-seq)
  51.         (go loop)
  52. exit-loop ; here, we know time of next note
  53.         ; (display "seq-midi" _next-time)
  54.         ; (format t "seq-midi calling snd-seq\n")
  55.         (return (snd-seq
  56.                   (set-logical-stop-abs _the-sound 
  57.                         (local-to-global _next-time))
  58.                   _seq-midi-closure)))))
  59.     ; (display "calling closure" (get-lambda-expression _seq-midi-closure))
  60.     (funcall _seq-midi-closure (local-to-global 0))))
  61.  
  62.  
  63. (defun seq-midi-cases-syntax-check (cases &aux n)
  64.   (cond ((not (listp cases))
  65.          (break "syntax error in" cases)))
  66.   (dolist (case cases)
  67.     (cond ((or (not (listp case)) 
  68.                (not (member (car case) '(NOTE CTRL BEND TOUCH PRGM)))
  69.                (not (listp (cdr case)))
  70.                (not (listp (cadr case)))
  71.                (not (listp (cddr case)))
  72.                (not (listp (last (cddr case)))))
  73.            (break "syntax error in" case))
  74.           ((/= (length (cadr case))
  75.                (setf n (cdr (assoc (car case) 
  76.                              '((NOTE . 3) (CTRL . 3) (BEND . 2)
  77.                                (TOUCH . 2) (PRGM . 2))))))
  78.            (break (format nil "expecting ~A arguments in" n) case))
  79.           ((and (eq (car case) 'NOTE)
  80.                 (not (member (length (cddr case)) '(1 2))))
  81.            (break 
  82.             "note handler syntax is (NOTE (ch pitch vel) [filter] behavior)"
  83.             case)))))
  84.  
  85.  
  86. (defun make-ctrl-handler (cases)
  87.   (let ((case (assoc 'ctrl cases)))
  88.     (cond (case
  89.            `(let ((,(caadr case) (seq-channel _the-event))
  90.                   (,(cadadr case) (seq-control _the-event))
  91.                   (,(caddar (cdr case)) (seq-value _the-event)))
  92.               ,@(cddr case)))
  93.           (t nil))))
  94.  
  95. (defun make-bend-handler (cases)
  96.   (let ((case (assoc 'bend cases)))
  97.     (cond (case
  98.            `(let ((,(caadr case) (seq-channel _the-event))
  99.                   (,(cadadr case) (seq-value _the-event)))
  100.               ,@(cddr case)))
  101.           (t nil))))
  102.  
  103. (defun make-touch-handler (cases)
  104.   (let ((case (assoc 'touch cases)))
  105.     (cond (case
  106.            `(let ((,(caadr case) (seq-channel _the-event))
  107.                   (,(cadadr case) (seq-value _the-event)))
  108.               ,@(cddr case)))
  109.           (t nil))))
  110.  
  111. (defun make-prgm-handler (cases)
  112.   (let ((case (assoc 'pgrm cases)))
  113.     (cond (case
  114.            `(let ((,(caadr case) (seq-channel _the-event))
  115.                   (,(cadadr case) (seq-value _the-event)))
  116.               ,@(cddr case)))
  117.           (t nil))))
  118.  
  119. (defun make-note-test (cases)
  120.   (let ((case (assoc 'note cases)))
  121.     (cond ((and case (cdddr case))
  122.            (caddr case))
  123.           (t t))))
  124.            
  125.  
  126. (defun make-note-handler (cases)
  127.   (let ((case (assoc 'note cases))
  128.         behavior)
  129.     (cond ((and case (cdddr case))
  130.            (setf behavior (cadddr case)))
  131.           (t
  132.            (setf behavior (caddr case))))
  133.     `(with%environment _nyq-environment
  134.         (with-note-args ,(cadr case) _the-event ,behavior))))
  135.  
  136.  
  137. (defmacro with-note-args (note-args the-event note-behavior)
  138.   ; (display "with-note-args" the-event)
  139.   `(let ((,(car note-args) (seq-channel ,the-event))
  140.          (,(cadr note-args) (seq-pitch ,the-event))
  141.          (,(caddr note-args) (seq-velocity ,the-event)))
  142.      (at (/ (seq-time ,the-event) 1000.0)
  143.       (stretch (/ (seq-duration ,the-event) 1000.0) ,note-behavior))))
  144.  
  145.  
  146. ;(defun seq-next-note-time (the-seq find-first-flag)
  147. ;  (prog (event)
  148. ;    (if find-first-flag nil (seq-next the-seq))
  149. ;loop
  150. ;    (setf event (seq-get the-seq))
  151. ;    (cond ((eq (seq-tag event) seq-done-tag)
  152. ;       (return (if find-first-flag 0.0 nil)))
  153. ;      ((eq (seq-tag event) seq-note-tag)
  154. ;       (return (/ (seq-time event) 1000.0))))
  155. ;    (seq-next the-seq)
  156. ;    (go loop)))
  157.